/* tools.c */

#include "public.h"
#include "scan.h"
#include "parser.h"
#include "tools.h"

/*  variable table search */
int find_tab(char *str)
{
	var_tab *p = tab_head;
	while(p != NULL)
	{
		if(!strcmp(str , p -> name))
			return p -> addr;
		p = p -> next;
	}
	return -1;
}

/* variable table insert */
void insert_tab(char *str)
{
	var_tab *p = tab_head;
	var_tab *q = tab_head;
	static int address = 0;
	while(p != NULL)
	{
		q = p;
		p = p -> next;
	}
	p = malloc(sizeof(var_tab));
	if(p == NULL)
		fprintf(syn_point, "at the line:%d, allocated memory error!\n", lineno);
	p -> addr = address++;
	p -> name = malloc(sizeof(token_str) + 1);
	strcpy(p -> name, str);
	if(tab_head == NULL)
		tab_head = p;
	else
		q -> next = p;
	p -> next = NULL;
}

/* my strcpy */
char *str_cpy(char *str)
{
	char *temp = (char *)malloc(strlen(str)+1);
	if(temp == NULL)
		fprintf(syn_point, "at the line:%d, allocated memory error!\n", lineno);
	else strcpy(temp, str);
	return temp;
}

/* malloc parser tree node */
parser_tree *malloc_stmt(stmt_kind stmt)
{
	parser_tree *tree;
	int i;
	tree = (parser_tree *)malloc(sizeof(parser_tree));
	if(tree == NULL)
		fprintf(syn_point, "allocated error! \n");
	else
	{
		for(i = 0; i < 3; i++)
			tree -> child[i] = NULL;
		tree -> next = NULL;
		tree -> base = stmt_b;
		tree -> lineno = lineno;
		(tree -> kind).stmt = stmt;
	}
	return tree;
}

parser_tree *malloc_exp(exp_kind exp)
{
	parser_tree *tree;
	int i;
	tree = (parser_tree *)malloc(sizeof(parser_tree));
	if(tree == NULL)
		fprintf(syn_point, "allocated error! \n");
	else
	{
		for(i = 0; i < 3; i++)
			tree -> child[i] = NULL;
		tree -> next = NULL;
		tree -> base = exp_b;
		tree -> lineno = lineno;
		(tree -> kind).exp = exp;
	}
	return tree;
}

/* variable table */
void print_variable(void)
{
	var_tab *p = tab_head;
	while(p != NULL)
	{
		fprintf(vari_point, "%d: %s\n", p -> addr, p -> name);
		p = p -> next;
	}
}

/* print token */
void print_token(token_type token, const char * token_str)
{
	switch(token)
	{
		case IF:
		case ELSE:
		case INT:
			/*        case RETURN:       */
		case VOID:
		case WHILE:
		case MAIN:
		case IN:
		case OUT:     fprintf(my_test, "Reserved word:%s\n", token_str); break;
		case PLUS:    fprintf(my_test, "+\n"); break;
		case MINUS:   fprintf(my_test, "-\n"); break;
		case TIMES:   fprintf(my_test, "*\n"); break;
		case DIVI:    fprintf(my_test, "//\n"); break;
		case LS:      fprintf(my_test, "<\n"); break;
		case LE:      fprintf(my_test, "<=\n"); break;
		case GT:      fprintf(my_test, ">\n"); break;
		case GE:      fprintf(my_test, ">=\n"); break;
		case EQ:      fprintf(my_test, "==\n"); break;
		case NE:      fprintf(my_test, "!=\n"); break;
		case ASSIGN:  fprintf(my_test, "=\n"); break;
		case SEMI:    fprintf(my_test, ";\n"); break;
		case COLO:    fprintf(my_test, ",\n"); break;
		case LPARE:   fprintf(my_test, "(\n"); break;
		case RPARE:   fprintf(my_test, ")\n"); break;
		case LBRA:    fprintf(my_test, "{\n"); break;
		case RBRA:    fprintf(my_test, "}\n"); break;
		case ID:      fprintf(my_test, "id = %s\n", token_str) ;break;
		case NUM:     fprintf(my_test, "num = %s\n", token_str) ;break;
		case ENDFILE: fprintf(my_test, "EOF\n"); break;
		default :     fprintf(my_test, "error\n");
	}
}


/* print parser tree */
static int n = 0;

void out_syn_tree(parser_tree *tree)
{
	int i;
	n += 1;
	while(tree != NULL)
	{
		for(i = 0; i < n; i++)
			fprintf(tree_tab, " ");
		if(tree -> base == stmt_b)
		{
			switch((tree -> kind).stmt)
			{
				case if_s:
					fprintf(tree_tab, "if\n");
					break;
				case while_s:
					fprintf(tree_tab, "while\n");
					break;
				case assign_s:
					fprintf(tree_tab, "%s =\n", (tree -> attribute).name);
					break;
				case in_s:
					fprintf(tree_tab, "in\n");
					break;
				case out_s:
					fprintf(tree_tab, "out\n");
					break;
				case null_s:
					fprintf(tree_tab, "null\n");
					break;
			}
		}
		else if(tree -> base == exp_b)
		{
			switch((tree -> kind).exp)
			{
				case op_e:
					fprintf(tree_tab, "op...\n");
					break;
				case const_e:
					fprintf(tree_tab, "%d\n",(tree -> attribute).value);
					break;
				case id_e:
					fprintf(tree_tab, "%s\n", (tree -> attribute).name);
					break;
				default:
					fprintf(tree_tab, "error!\n");
					break;

			}
		}
		else 
			fprintf(tree_tab, "error!\n");
		for(i = 0; i < 3; i++)
		{
			if(tree -> child[i])
				out_syn_tree(tree -> child[i]);
		}
		tree = tree -> next;
	}/* end while */
	/* fprintf(tree_tab, "***********************************\n"); */
	n -= 1;
}

void free_tree(parser_tree *tree)
{
	if(tree != NULL)
	{
		free_tree(tree -> next);
		free_tree(tree -> child[0]);
		free_tree(tree -> child[1]);
		free_tree(tree -> child[2]);
		free(tree);
		tree = NULL;
	}
}

/* generate asm code */
void write_null(char *str)
{
	fprintf(cfile_ptr, "%3d: %s\n", asm_addr++, str);
}

void write_in(void)
{
	fprintf(cfile_ptr, "%3d: in ax\n", asm_addr++);
}

void write_mov_mem(int addr, char *str)
{
	fprintf(cfile_ptr, "%3d: mov %d, %s\n", asm_addr++, addr, str);
}

void write_mov_reg(char *str, int addr)
{
	fprintf(cfile_ptr, "%3d: mov %s, %d\n", asm_addr++, str, addr);
}

void write_out(void)
{
	fprintf(cfile_ptr,"%3d: out ax\n", asm_addr++);
}

void save_curr_addr(int *curr_addr)
{
	*curr_addr = asm_addr;
}

void skip_curr_addr(void)
{
	++asm_addr;
}

void write_jmp(char *str, int addr)
{
	fprintf(cfile_ptr, "%3d: %s %d\n", asm_addr++, str, addr);
}

void back_patch(int addr)
{
	asm_addr = addr;
}

void mov_ax_num(int data)
{
	fprintf(cfile_ptr, "%3d: mov ax, #%d\n", asm_addr++, data);
}

void write_push(void)
{
	fprintf(cfile_ptr, "%3d: push ax\n", asm_addr++);
}

void write_pop(void)
{
	fprintf(cfile_ptr, "%3d: pop dx\n", asm_addr++);
}

void write_swap(void)
{
	fprintf(cfile_ptr, "%3d: xchg ax, dx\n", asm_addr++);
}

void write_cal(char *str)
{
	fprintf(cfile_ptr, "%3d: %s ax, dx\n", asm_addr++, str);
}
